#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace KLib.Physics.Collisions
{
    public class Vertices : List<Vector2>
    {
        #region Fields

        #endregion

        #region Properties
        public Vector2[] VertexArray
        {
            get
            {
                return this.ToArray();
            }
            set
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this[i] = value[i];
                }
            }
        }
        #endregion

        #region Initialization
        public Vertices() { }
        public Vertices(Vector2[] vertices)
        {
            for (int i = 0; i < vertices.Length; i++)
                this.Add(vertices[i]);
        }

        public Vertices(Vertices verticies)
        {
            for (int i = 0; i < verticies.Count; i++)
                this.Add(verticies[i]);
        }

        #endregion

        #region Methods

        public int NextIndex(int index)
        {
            if (index >= this.Count - 1)
                return 0;
            else
                return index + 1;
        }

        public int PreviousIndex(int index)
        {
            if (index <= 0)
                return this.Count - 1;
            else
                return index - 1;
        }

        /// <summary>
        /// Moves all the Vertices by a specific amount.
        /// </summary>
        /// <param name="amount"></param>
        public void Translate(Vector2 amount)
        {
            for (int i = 0; i < this.Count; i++)
                this[i] = Vector2.Add(this[i], amount);
        }

        Vector2 tmpVect1;
        Vector2 tmpVect2;
        Vector2 tmpVect3;

        public Vector2 GetEdge(int index)
        {
            int nextIndex = NextIndex(index);
            tmpVect1 = this[nextIndex];
            tmpVect2 = this[index];

            return Vector2.Subtract(tmpVect1, tmpVect2);
        }
        public Vector2 GetEdgeNormal(int index)
        {
            tmpVect1 = GetEdge(index);
            tmpVect2.X = -tmpVect1.Y;
            tmpVect2.Y = tmpVect1.X;

            return Vector2.Normalize(tmpVect2);
        }

        public Vector2 GetVertexNormal(int index)
        {
            tmpVect1 = GetEdgeNormal(index);

            int prvIndex = PreviousIndex(index);
            tmpVect2 = GetEdgeNormal(prvIndex);

            tmpVect3 = Vector2.Add(tmpVect1, tmpVect2);

            Vector2.Normalize(ref tmpVect3, out tmpVect1);

            return tmpVect1;
        }
        #endregion

        #region Helper Methods
        public float GetSignedArea()
        {
            int i, j;
            float area = 0;

            for (i = 0; i < Count; i++)
            {
                j = (i + 1) % Count;
                area += this[i].X * this[j].Y;
                area -= this[i].Y * this[j].X;
            }
            area /= 2.0f;
            return area;
        }
        #endregion

        #region Static
        /// <summary>
        /// Creates a new Set of vertices to make a Rectangle at the specifed Width and Height
        /// </summary>
        /// <param name="width">The Width of the Rectangle to create</param>
        /// <param name="height">The Height of the Rectangle to create</param>
        /// <returns>The Vertices that make the Rectangle at the specified width and height</returns>
        public static Vertices CreateRectangle(float width, float height)
        {
            Vertices vertices = new Vertices();
            vertices.Add(new Vector2(-width * .5f, -height * .5f));
            vertices.Add(new Vector2(-width * .5f, -height * .25f));
            vertices.Add(new Vector2(-width * .5f, 0));
            vertices.Add(new Vector2(-width * .5f, height * .25f));
            vertices.Add(new Vector2(-width * .5f, height * .5f));
            vertices.Add(new Vector2(-width * .25f, height * .5f));
            vertices.Add(new Vector2(0, height * .5f));
            vertices.Add(new Vector2(width * .25f, height * .5f));
            vertices.Add(new Vector2(width * .5f, height * .5f));
            vertices.Add(new Vector2(width * .5f, height * .25f));
            vertices.Add(new Vector2(width * .5f, 0));
            vertices.Add(new Vector2(width * .5f, -height * .25f));
            vertices.Add(new Vector2(width * .5f, -height * .5f));
            vertices.Add(new Vector2(width * .25f, -height * .5f));
            vertices.Add(new Vector2(0, -height * .5f));
            vertices.Add(new Vector2(-width * .25f, -height * .5f));
            return vertices;
        }

        /// <summary>
        /// Creates a new set of Verticies to make a Circle of the specifed radius, with a specified number of edges.
        /// </summary>
        /// <param name="radius">The Radius of the Circle</param>
        /// <param name="edgeCount">The number of edges the circle has. More edges will result in more circular behavior at the cost of preformance</param>
        /// <returns>The Vertices that make the Circle of the specifed Radius with the specified number of edges</returns>
        public static Vertices CreateCircle(float radius, float edgeCount)
        {
            Vertices vertices = new Vertices();
            float stepSize = MathHelper.TwoPi / (float)edgeCount;
            for (int i = 1; i < edgeCount; i++)
                vertices.Add(new Vector2(radius * (float)Math.Cos(stepSize * i), -radius * (float)Math.Sin(stepSize * i)));
            return vertices;
        }
        #endregion

        #region ToString()
        public override string ToString()
        {
            string returnString = String.Empty;
            for (int i = 0; i < this.Count; i++)
            {
                returnString += this[i].ToString();
                if (i < this.Count-1)
                    returnString += " ";
            }
            return returnString;
        }
        #endregion
    }
}
